Proxy 字面上是「代理」的意思,意味著當我們要做去做一些事情前,會先透過代理的這一層,之後才交給真正的物件做處理。我們在現實生活中,就有蠻多會遇到 Proxy 的例子,例如當雙十一時,每個人都在店商網站上瘋狂購物,對於後端伺服器的請求量就會相當大,這時候就可以使用Proxy。
當使用者發送請求後,他會先呼叫到的是一個代理伺服器,這邊會去判斷說他要做的操作,再決定是否要真正將請求再丟給真實伺服器去處理。我們以今天的例子來看,如果請求是成功的,那我就會做紀錄,下次有同樣請求再來時,我就直接將結果回傳,就不用再丟給後端伺服器,也就能夠減少後端伺服器的資料處理量以及負擔。
爲其他物件提供一種代理以控制對這個物件的訪問。
(圖片來源:https://zh.wikipedia.org/wiki/代理模式#/media/File:Proxy_pattern_diagram.svg)
IHandler
是 RealServer
以及 ProxyServer
的共通介面,會定義需要實作的方法。RealServer
會去資料庫取出資料(這邊用隨機 Random
表示是否有成功從資料庫取出資料)。ProxyServer
會去呼叫RealServer
,如果有從資料庫取資料成功,則將這次請求記錄起來,如果下次又有同樣的請求來時,就直接回傳結果,不再呼叫RealServer
。using System;
using System.Collections.Generic;
namespace DAY24_Proxy
{
public class Program
{
static void Main(string[] args)
{
IHandler proxyServer = new ProxyServer();
// 同樣的請求執行兩輪,如果上次請求成功,代理伺服器即直接回傳,否則呼叫真實伺服器
for (int loop = 0; loop < 2; loop++)
{
for (int x = 0; x < 5; x++)
{
proxyServer.HandleRequest($"請求{x}");
}
}
}
}
// 定義共通介面
public interface IHandler
{
bool HandleRequest(string request);
}
public class RealServer : IHandler
{
// 實作介面,並從資庫取資料
public bool HandleRequest(string request)
{
Console.WriteLine($"{request},開始處理");
return GetDataFromDatabase(request);
}
private bool GetDataFromDatabase(string request)
{
bool result;
Random rnd = new Random();
var isSuccess = rnd.Next(10)%2 == 0;
if (isSuccess)
{
Console.WriteLine($"{request} => 從資料庫取出資料成功!\n");
result = true;
}
else
{
Console.WriteLine($"{request} => 從資料庫取出資料失敗!\n");
result = false;
}
return result;
}
}
public class ProxyServer : IHandler
{
private readonly List<string> _requestLists;
private readonly RealServer _realServer;
public ProxyServer()
{
_realServer = new RealServer();
_requestLists = new List<string>();
}
public bool HandleRequest(string request)
{
bool result;
// 代理伺服器會先尋找同樣請求之前是否有成功,有則直接回傳true,沒有則呼叫真實伺服器
if (_requestLists.Contains(request)) {
Console.WriteLine($"{request}已有紀錄,直接回傳成功!\n");
result = true;
}
else
{
// 如果請求成功,代理伺服器會將請求字串存入List,以便下次再來同個請求即可直接回傳true
result = _realServer.HandleRequest(request);
if (result) _requestLists.Add(request);
}
return result;
}
}
}
透過 Proxy 模式,我們可以先在代理部分做判斷,再去呼叫真實物件做處理,這樣用代理伺服器的好處除了能減少後端的負擔,同時我們也能夠在代理伺服器就先過濾掉可能的危險請求,以保證送去後端的請求是安全的。當然上面例子只是代理模式的其中一種應用,還有很多像是防火牆或是虛擬代理人等等的模式應用,這部分未來有機會再做成一篇文章跟大家介紹。